package com.apes.enquiry.supplier.baturu.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.enquiry.enquiry.model.QuoteResult;
import com.apes.enquiry.enquiry.repository.QuoteResultRepository;
import com.apes.enquiry.orderForm.model.OrderForm;
import com.apes.enquiry.orderForm.model.OrderFormDetail;
import com.apes.enquiry.orderForm.repository.OrderFormRepository;
import com.apes.enquiry.supplier.baturu.BaturuApi;
import com.apes.enquiry.supplier.baturu.BaturuService;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.Tools;
import com.apes.scm.masterdata.frame.model.Store;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.masterdata.stock.model.PhyDepot;
import com.apes.framework.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 类描述：
 *
 * @ClassName BaturuCodingService
 * @Description 描述
 * @Author wushilong
 * @Date 2023/4/24 13:37
 * @Version 1.0
 */
@Service
public class BaturuCodingService extends DomainService {

    @Autowired
    private BaturuApi baturuApi;

    @Autowired
    private BaturuService baturuService;

    @Autowired
    private QuoteResultRepository quoteResultRepository;

    @Autowired
    private BaturuAccountInfoService baturuAccountInfoService;

    @Autowired
    private OrderFormRepository orderFormRepository;

    /**
     * 车架号获取车型信息
     *
     * @param request {"vinCode":"车架号"}
     * @return
     */
    public JSONObject queryCarTypeByVin(SimpleRequest request) {
        JSONObject requestJO = request.getJO();

        JSONObject vinMessage = baturuApi.queryCarTypeByVin(requestJO);
        if (Objects.isNull(vinMessage.getJSONObject("model"))) throw new RuntimeException("您输入车牌号的VIN码有误，请核对后再输入~");
        JSONArray carTypes = vinMessage.getJSONObject("model").getJSONArray("carTypes");
        List<String> carTypeIds = carTypes.stream().map(o -> {
            return ((JSONObject) o).getString("carTypeId");
        }).collect(Collectors.toList());
        vinMessage.getJSONObject("model").put("carTypeIds", carTypeIds);
        return vinMessage;
    }

    /**
     * 根据 vin 码和配件别名查询配件标准名称
     *
     * @param request {"vinCode":"车架号（选填）", "keyword":"配件别名（必填）"}
     * @return
     */
    public JSONObject searchPartsHintsInfo(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        return baturuApi.searchPartsHintsInfo(requestJO);
    }

    /**
     * 根据 vin+配件名称带出epc图片、OE号等信息
     * @param request {"carTypeIds":[车型id集合]，"partsNames":["配件名称“], "vinAnalyseSource":车架号解析来源, "vinCode":"车架号", "brandName":"车品牌（）"}
     * @return
     */
    public JSONObject queryPartsCodeInfo(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        if (requestJO.getJSONArray("carTypeIds").size() != 1) {
            requestJO.put("carTypeIds", Arrays.asList(requestJO.getJSONArray("carTypeIds").stream().findFirst().get()));
        }
        JSONObject partsCode = baturuApi.queryPartsCodeInfo(requestJO);
        partsCode.put("vinCode", requestJO.getString("vinCode"));
        partsCode.put("brandName", requestJO.getString("brandName"));
        partsCode.put("vinAnalyseSource", requestJO.getString("vinAnalyseSource"));
        JSONArray model = partsCode.getJSONArray("model");
        if (model.getJSONObject(0).getJSONArray("partsInfos").size() == 0) {
            //没有查到根据配件编码再查一次
            model = queryPartsName(request, model);
        }
        for (Object o : model) {
            JSONObject item = (JSONObject) o;
            JSONArray partsInfos = item.getJSONArray("partsInfos");
            //配件大于一个舍弃
            if (partsInfos.size() != 1) {
                item.remove("partsInfos");
                item.remove("partsCodes");
                //记录译码
                transactionOutbox(request,partsCode);
                return partsCode;
            }
            item.put("partsInfos", partsInfos.get(0));
            item.put("partsCodes", item.getJSONArray("partsCodes").get(0));
            //处理巴图鲁返回的图片，转换成我们自己的格式
            disposePicture(item);
            query4sPrice(item, requestJO.getString("brandName"));
        }
        //记录译码
        transactionOutbox(request,partsCode);
        return partsCode;
    }

    private JSONArray queryPartsName(SimpleRequest request, JSONArray model) {
        JSONObject result = queryPartsName(request);
        if (StringUtils.isEmpty(result.getString("model")) || result.getJSONArray("model").size() == 0) return model;
        JSONObject PartsName = result.getJSONArray("model").getJSONObject(0);
        JSONObject item = model.getJSONObject(0);
        item.put("standardName", PartsName.getString("partsName"));
        item.put("partsName", PartsName.getString("partsName"));
        item.put("partsCodes", Arrays.asList(PartsName.getString("partsCode")));

        JSONObject image = queryOEImage(request);
        if (image.getJSONArray("model") == null) return model;
        item.getJSONArray("partsInfos").addAll(image.getJSONArray("model"));

        return model;
    }

    /**
     * 替换编码接口
     *
     * @param request {"partsCodes":["查询配件编码"]，"vin":"车架号（选填）", "brand":"车品牌（选填）"}
     * @return
     */
    public JSONObject queryPartsReplaceCode(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        return baturuApi.queryPartsReplaceCode(requestJO);
    }

    /**
     * 编码带出配件主名
     *
     * @param request
     * @return
     */
    public JSONObject queryPartsName(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        JSONObject param = new JSONObject();
        param.put("partsCodes", requestJO.getJSONArray("partsNames"));
        param.put("vin", requestJO.getString("vinCode"));
        param.put("brand", requestJO.getString("brandName"));
        return baturuService.queryPartsName(param);
    }

    /**
     * 编码带出epc图片
     *
     * @param request
     * @return
     */
    public JSONObject queryOEImage(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        JSONObject param = new JSONObject();
        param.put("partsCodes", requestJO.getJSONArray("partsNames"));
        param.put("vinCode", requestJO.getString("vinCode"));
        param.put("brand", requestJO.getString("brandName"));
        return baturuService.queryOEImage(param);
    }

    /**
     * 处理巴图鲁返回的图片，转换成我们自己的格式
     *
     * @param item
     */
    public void disposePicture(JSONObject item) {
        JSONObject partsInfos = item.getJSONObject("partsInfos");
        JSONArray epcPartsImages = partsInfos.getJSONArray("epcPartsImages");
        JSONArray pictures = new JSONArray();
        for (Object o : epcPartsImages) {
            JSONObject epcPartsImage = (JSONObject) o;
            JSONArray epcPartsImagePositionDTOs = epcPartsImage.getJSONArray("epcPartsImagePositionDTOs");
            JSONObject picture = new JSONObject();
            picture.put("url", StringUtil.urlGetFile("https:" + epcPartsImage.getString("imageUrl")));
            for (Object j: epcPartsImagePositionDTOs) {
                JSONObject epcPartsImagePositionDTO = (JSONObject) j;
                JSONObject bottomRight = epcPartsImagePositionDTO.getJSONObject("bottomRight");
                JSONObject topLeft = epcPartsImagePositionDTO.getJSONObject("topLeft");
                //我们平台的图片坐标
                JSONObject points = new JSONObject();
                points.put("x", topLeft.getInteger("x"));
                points.put("y", topLeft.getInteger("y"));
                points.put("h", bottomRight.getInteger("y") - topLeft.getInteger("y"));
                points.put("w", bottomRight.getInteger("x") - topLeft.getInteger("x"));
                points.put("sn", epcPartsImagePositionDTO.getString("position"));
                picture.put("points", Arrays.asList(points));
            }
            pictures.add(picture);
        }
        partsInfos.put("pictures", pictures.toString());
    }

    /**
     * 获取4S价格
     *
     * @param partsCode
     * @param brandName
     */
    public void query4sPrice(JSONObject partsCode, String brandName) {
        String partsCodeId = partsCode.getString("partsCodes");
        JSONObject param = new JSONObject();
        param.put("partsCodes", Arrays.asList(partsCodeId));
        JSONObject queryPrice = baturuApi.query4sPrice(param);
        JSONArray model = queryPrice.getJSONArray("model");
        if (Objects.isNull(model)) return;
        for (Object o : model) {
            JSONObject item = (JSONObject) o;
            if (item.getString("brandName").equals(brandName)){
                partsCode.getJSONObject("partsInfos").put("price", item.getDouble("price"));
            }
        }
    }



    /**
     * 事务发件箱
     *
     */
    public void transactionOutbox(SimpleRequest request,JSONObject partsCode) {
        OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
        wrapper.setSubscriber("dc.record.coding");
        SimpleDateFormat sdf = new SimpleDateFormat("yy-mm-dd HH:mm:ss");
        String random = String.valueOf(Math.random()).substring(0, 3);
        wrapper.setAggregateId(request.getJO().getString("brandName")+ sdf.format(new Date()) + random);//聚合根ID（非必项）tp:方便追溯发生异常的服务,最好是业务单据单号
        wrapper.setPayload(JSON.toJSONString(partsCode));
        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);

    }

    /**
     *巴图鲁记录译码
     * @param outboxPayloadWrapper 传入译码的商品
     */
    @OutboxSubscriber(id = "dc.record.coding", name = "通过事务发件箱记录巴图鲁译码数据")
    public void standardContrast(OutboxPayloadWrapper outboxPayloadWrapper) {
        JSONObject jsonObject = JSON.parseObject(outboxPayloadWrapper.getPayload());
        if (jsonObject==null) return;
       JSONObject jo = JSONObject.parseObject(invoke("dc.supplierCodingRecord.supplierCodingRecordInsert",jsonObject));
       if(jo.getString("body")==null){
           throw new RuntimeException("记录译码失败！");
       }
    }

    /**
     * 向巴图鲁下订单
     *
     * @param orderForm
     * @param productRequireItems OrderForm orderForm, JSONArray productRequireItems
     * @return
     */
    public JSONObject orderForm(OrderForm orderForm, JSONArray productRequireItems) {
        if (CollectionUtils.isEmpty(productRequireItems)) {
            return new JSONObject();
        }
        //拼接请求参数
        JSONArray orderDetails = new JSONArray();
        productRequireItems.forEach(item -> {
            JSONObject detail = (JSONObject) item;
            if (StringUtils.isEmpty(detail.getString("channelType")) || detail.getInteger("channelType") != 5) return;
            //拼接请求对象参数
            JSONObject orderDetail = packageOrderDetails(detail);
            orderDetails.add(orderDetail);
        });
        if (orderDetails.isEmpty()) return new JSONObject();
        JSONObject detail = (JSONObject) productRequireItems.get(0);
        JSONObject request = packageData(orderForm,detail);
        request.put("orderDetails",orderDetails);
        JSONObject response = baturuApi.createOrder(request);
        return response;
    }

    /**
     * 封装数据（userKey: 用户标识，receiverAddress：地址信息，orderDetails：订单信息）
     *
     * @param orderForm
     * @return
     */
    private JSONObject packageData(OrderForm orderForm,JSONObject detail) {
        JSONObject result = new JSONObject();

        //从erp系统获取门店信息
        JSONObject param = new JSONObject();
        param.put("id",orderForm.getClientId());
        JSONObject storeData = invoke("cm.store.findOne", param);
        Store store = Tools.map(storeData, Store.class);
        JSONObject body = null;
        if (com.apestech.framework.util.StringUtil.isNotEmpty(orderForm.getSource()) && !orderForm.getSource().startsWith("DS")) {
            JSONObject servicePlan = JSONObject.parseObject(invoke("fn.servicePlan.findOne", MapUtil.mapper("id", orderForm.getSource())));
            JSONObject belongDept = servicePlan.getJSONObject("body").getJSONObject("belongDept");
            JSONObject locationDepts = JSONObject.parseObject(invoke("fn.service.getLocationByDept", MapUtil.mapper("deptId", belongDept.getString("id"))));
            body = locationDepts.getJSONArray("body").getJSONObject(0);
        }else {
            JSONObject productRequire = JSONObject.parseObject(invoke("stock.productRequire.findOneNoAuto", MapUtil.mapper("id", orderForm.getRelatedNumber())));
            JSONObject location1 = productRequire.getJSONObject("body").getJSONObject("location");
            JSONObject location2 = JSONObject.parseObject(invoke("cm.location.findOne", MapUtil.mapper("id", location1.getString("id"))));
            body = location2.getJSONObject("body");
        }
        Location location = Tools.map(body, Location.class);
        JSONObject phyDepotJSON = JSONObject.parseObject(invoke("cm.phyDepot.findOne",MapUtil.mapper("id",location.getPhyDepot().getId())));
        PhyDepot phyDepot = Tools.map(phyDepotJSON.getJSONObject("body"), PhyDepot.class);

        JSONObject receiverAddress = new JSONObject();
        receiverAddress.put("location", phyDepot.getLongitude() + "," + phyDepot.getLatitude());
        receiverAddress.put("address", phyDepot.getAddress());

        //获取门店联系人
        JSONObject contact = detail.getJSONObject("store");
        String userKey = baturuAccountInfoService.queryUserKey(store.getCode());
        result.put("receiverAddress", receiverAddress);
        result.put("userKey", userKey);
        result.put("receiverName", contact.getString("contacts"));
        result.put("receiverPhone", contact.getString("telephone"));
        result.put("bothPay", true);
        result.put("payType", 2);
        return result;
    }

    /**
     * 封装订单明细信息
     * @param detail
     * @return
     */
    private JSONObject packageOrderDetails(JSONObject detail){
        //从报价结果表中获取巴图鲁报价单号
        String spId = detail.getString("spId");
        String[] split = spId.split("/");
        QuoteResult quoteResult = quoteResultRepository.findOne(split[0]);

        detail.put("priceNo",quoteResult.getPriceNo());
        JSONObject orderDetail = new JSONObject();
        orderDetail.put("priceNo", quoteResult.getPriceNo());
        orderDetail.put("num", detail.getString("qtyRequire"));
        orderDetail.put("invoiceType", -1);
        orderDetail.put("specificCarrier", true);
        orderDetail.put("carrierId", -10L);
        orderDetail.put("carrierName", "其他物流");
        return orderDetail;
    }

    /**
     * 巴图鲁取消采购订单
     * @param request
     */
    public void baturuEndOrder(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        JSONObject data = requestJO.getJSONObject("data");
        String orderNo = data.getString("orderNo");
        //获取订单信息
        OrderForm orderForm = orderFormRepository.findAll(JpaDsl.toCriteriaByEq("supplierNumber", orderNo)).stream().findFirst().orElse(null);
        if (ObjectUtils.isEmpty(orderForm)) return;

        OrderFormDetail orderFormDetail = orderForm.getDetailList().stream().filter(item ->
                item.getOrderQuantity() != (item.getAOGNumber() + item.getTerminationNumber())).findFirst().orElse(null);
        if (ObjectUtils.isEmpty(orderFormDetail)) return;

        JSONArray orderDetailList = data.getJSONArray("orderDetailList");
        orderDetailList.forEach(orderDetail -> {
            JSONObject orderDetailObj = (JSONObject) orderDetail;
            Integer cancelNum = orderDetailObj.getInteger("cancelNum");
            orderForm.getDetailList().forEach(item -> {
                if (orderDetailObj.getString("priceNo").equals(item.getPriceNo())){
                    if (item.getOrderQuantity() < cancelNum) return;
                    item.setTerminationNumber(cancelNum);
                    item.setTerminationDate(new Date());
                }
            });
        });
        orderFormRepository.saveAndFlush(orderForm);
    }
}
